package cn.com.pagoda.ideplugin.service;

import com.intellij.openapi.actionSystem.AnActionEvent;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;

import javax.swing.*;
import java.io.StringWriter;
import java.util.*;

/**
 * @author <a href="mailto:kindbgen@gmail.com">Kindbgen<a/>
 * @description YAML-Properties互转实现
 * @date 2023/6/10
 * @since 1.0.0
 */
public class YamlPropertiesConverterService {

    private final AnActionEvent anActionEvent;
    private final JPanel panel;
    private JTextArea yamlTextArea;
    private JTextArea propertiesTextArea;

    public YamlPropertiesConverterService(AnActionEvent anActionEvent, JPanel panel, JTextArea yamlTextArea, JTextArea propertiesTextArea) {
        this.anActionEvent = anActionEvent;
        this.panel = panel;
        this.yamlTextArea = yamlTextArea;
        this.propertiesTextArea = propertiesTextArea;
    }

    /**
     * YAML 转 Properties
     */
    public void convertToProperties() {
        String yamlText = yamlTextArea.getText().trim();
        if (yamlText.isEmpty()) {
            propertiesTextArea.setText("");
            return;
        }

        if (!yamlText.contains(":")) {
            propertiesTextArea.setText("Invalid YAML format!");
            return;
        }

        try {
            Yaml yaml = new Yaml(new SafeConstructor());
            Map<String, Object> data = yaml.load(yamlText);

            Properties properties = new Properties();
            convertMapToProperties("", data, properties);

            propertiesTextArea.setText(propertiesToString(properties));
        } catch (Exception e) {
            propertiesTextArea.setText("Invalid YAML format!    exception look >> " + e.getMessage());
        }
    }

    /**
     * MAP 转 Properties
     *
     * @param prefix
     * @param data
     * @param properties
     */
    public void convertMapToProperties(String prefix, Map<String, Object> data, Properties properties) {
        for (Map.Entry<String, Object> entry : data.entrySet()) {
            String key = prefix + entry.getKey();
            Object value = entry.getValue();
            if (value instanceof Map) {
                convertMapToProperties(key + ".", (Map<String, Object>) value, properties);
            } else {
                properties.put(key, Objects.nonNull(value) ? value.toString() : "");
            }
        }
    }

    /**
     * Properties 转 String
     */
    public String propertiesToString(Properties properties) {
        StringBuilder sb = new StringBuilder();
        for (String key : properties.stringPropertyNames()) {
            String value = properties.getProperty(key);
            sb.append(key).append("=").append(value).append("\n");
        }
        return sb.toString();
    }

    /**
     * Properties 转 YAML
     */
    public void convertToYaml() {
        String propertiesText = propertiesTextArea.getText().trim();
        if (propertiesText.isEmpty()) {
            yamlTextArea.setText("");
            return;
        }

        try {
            Properties properties = new Properties();
            properties.load(new java.io.StringReader(propertiesText));

            Map<String, Object> yamlMap = new LinkedHashMap<>();

            for (String key : properties.stringPropertyNames()) {
                String[] keyParts = key.split("\\.");

                Map<String, Object> currentMap = yamlMap;
                for (int i = 0; i < keyParts.length - 1; i++) {
                    String keyPart = keyParts[i];

                    if (!currentMap.containsKey(keyPart)) {
                        Map<String, Object> newMap = new LinkedHashMap<>();
                        currentMap.put(keyPart, newMap);
                        currentMap = newMap;
                    } else {
                        Object existingValue = currentMap.get(keyPart);
                        if (existingValue instanceof Map) {
                            currentMap = (Map<String, Object>) existingValue;
                        } else {
                            Map<String, Object> newMap = new LinkedHashMap<>();
                            newMap.put("", existingValue);
                            currentMap.put(keyPart, newMap);
                            currentMap = newMap;
                        }
                    }
                }

                String finalKeyPart = keyParts[keyParts.length - 1];
                String propertyValue = properties.getProperty(key);
                currentMap.put(finalKeyPart, propertyValue);
            }

            DumperOptions options = new DumperOptions();
            options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
            options.setPrettyFlow(true);

            Yaml yaml = new Yaml(options);
            StringWriter writer = new StringWriter();
            yaml.dump(yamlMap, writer);

            String yamlText = writer.toString();
            yamlText = removeQuotesFromScalars(yamlText);

            yamlTextArea.setText(yamlText);
        } catch (Exception e) {
            yamlTextArea.setText("Invalid Properties format!    exception look >> " + e.getMessage());
        }
    }

    /**
     * 去掉单引号和双引号
     *
     * @param yamlText
     * @return
     */
    private String removeQuotesFromScalars(String yamlText) {
        StringBuilder builder = new StringBuilder();
        Scanner scanner = new Scanner(yamlText);
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine();
            if (line.matches("\\s*[-]?\\s*(\\d+(\\.\\d+)?)|true|false\\s*")) {
                builder.append(line).append(System.lineSeparator());
            } else {
                builder.append(line.replaceAll("['\"]", "")).append(System.lineSeparator());
            }
        }
        return builder.toString();
    }

}
